<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>JavaScript的单线程问题及同步和异步 | ACERY</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="JavaScript的单线程问题同步和异步阻塞和非阻塞的概念
阻塞：线程在执行I/O操作（磁盘读取或网络通信）会耗时较长，操作系统剥夺该线程的CPU控制权，使其暂停工作，直至完成该操作为止，再恢复其对CPU的控制权。以上称为同步式I/O（Synchronous）或阻塞式I/O。
   JS中实例表现  
document.onclick=function(){
    console.log(&amp;a">
<meta property="og:type" content="article">
<meta property="og:title" content="JavaScript的单线程问题及同步和异步">
<meta property="og:url" content="http://yoursite.com/2016/11/20/JavaScript的单线程问题及同步和异步/index.html">
<meta property="og:site_name" content="ACERY">
<meta property="og:description" content="JavaScript的单线程问题同步和异步阻塞和非阻塞的概念
阻塞：线程在执行I/O操作（磁盘读取或网络通信）会耗时较长，操作系统剥夺该线程的CPU控制权，使其暂停工作，直至完成该操作为止，再恢复其对CPU的控制权。以上称为同步式I/O（Synchronous）或阻塞式I/O。
   JS中实例表现  
document.onclick=function(){
    console.log(&amp;a">
<meta property="og:image" content="http://i.imgur.com/B7JaHkJ.png">
<meta property="og:image" content="http://i.imgur.com/MFHxGhX.png">
<meta property="og:image" content="http://i.imgur.com/fDlN6a5.png">
<meta property="og:updated_time" content="2016-11-20T06:41:59.659Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="JavaScript的单线程问题及同步和异步">
<meta name="twitter:description" content="JavaScript的单线程问题同步和异步阻塞和非阻塞的概念
阻塞：线程在执行I/O操作（磁盘读取或网络通信）会耗时较长，操作系统剥夺该线程的CPU控制权，使其暂停工作，直至完成该操作为止，再恢复其对CPU的控制权。以上称为同步式I/O（Synchronous）或阻塞式I/O。
   JS中实例表现  
document.onclick=function(){
    console.log(&amp;a">
<meta name="twitter:image" content="http://i.imgur.com/B7JaHkJ.png">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
  

</head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">ACERY</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">主页</a>
        
          <a class="main-nav-link" href="/categories/JS">JavaScript</a>
        
          <a class="main-nav-link" href="/categories/CS">ComputerScience</a>
        
      </nav>
      <nav id="sub-nav">
        
        <a id="nav-search-btn" class="nav-icon" title="搜索"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-JavaScript的单线程问题及同步和异步" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2016/11/20/JavaScript的单线程问题及同步和异步/" class="article-date">
  <time datetime="2016-11-20T06:37:37.000Z" itemprop="datePublished">2016-11-20</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/JS/">JS</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      JavaScript的单线程问题及同步和异步
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="JavaScript的单线程问题"><a href="#JavaScript的单线程问题" class="headerlink" title="JavaScript的单线程问题"></a>JavaScript的单线程问题</h2><h2 id="同步和异步"><a href="#同步和异步" class="headerlink" title="同步和异步"></a>同步和异步</h2><h4 id="阻塞和非阻塞的概念"><a href="#阻塞和非阻塞的概念" class="headerlink" title="阻塞和非阻塞的概念"></a>阻塞和非阻塞的概念</h4><hr>
<p><strong>阻塞：</strong><br>线程在执行I/O操作（磁盘读取或网络通信）会耗时较长，操作系统剥夺该线程的CPU控制权，使其暂停工作，直至完成该操作为止，再恢复其对CPU的控制权。以上称为同步式I/O（Synchronous）或阻塞式I/O。</p>
<p>   JS中实例表现  </p>
<pre><code>document.onclick=function(){
    console.log(&apos;hello&apos;);
}
for(var i=0;i&lt;=19900000000;i++);
</code></pre><p>当其执行耗时操作时，该点击事件将无响应。</p>
<p>而此处的事件绑定是个异步事件，会先将该任务添加进 ‘任务队列’，当处理栈（js主线程）里没任务时，才会调取队列里的任务运行。</p>
<p>阻塞（同步）图解</p>
<p><img src="http://i.imgur.com/B7JaHkJ.png" alt=""></p>
<p>绿色部分为程序正常运行的时间，红色代表等待请求或者处理所花时间，而在该时间段里，用户是不能进行操作的，即会出现’假死’状态。此种称为阻塞（同步）I/O。</p>
<hr>
<p><strong>非阻塞：（Asynchronous）</strong><br>当线程遇到I/O操作时，不会以阻塞的方式等待I/O操作的完成或数据的返回，而只是将该请求发给操作系统，并继续执行下一条语句，但完成I/O操作后，会以事件的形式通知该线程。这种模式叫非阻塞模式，也叫异步模式（asynchronous）；</p>
<p>对于JS，采用了EventLoop的并发模型 </p>
<p><img src="http://i.imgur.com/MFHxGhX.png" alt=""><br>当该线程遇到I/O操作时，会通知Event Loop 去调用cpu去进行，而主线程会接着往后运行，即不存在阻塞的时间，当I/O操作完成后，event loop再把结果返回主线程，该模式多出了更多的时间以处理更多的任务。</p>
<p><strong>多线程与单线程</strong></p>
<hr>
<p>多线程的好处是可以在多核的情况下尽可能的利用更多核进行运算。多线程可以提高吞吐量，提高并发的能力。</p>
<p>单线程的好处是可以提高单核的运算效率，因为在单线程非阻塞的模式下，该线程调用的cpu一直处于工作状态下，除非完成工作。</p>
<hr>
<p>Node.js采用的是单线程，非阻塞的模式。</p>
<p><strong>进程和线程</strong></p>
<blockquote>
<p>进程和线程都是操作系统的概念。进程是应用程序的执行实例，每一个进程都是由私有的虚拟地址空间、代码、数据和其它系统资源所组成；进程在运行过程中能够申请创建和使用系统资源（如独立的内存区域等），这些资源也会随着进程的终止而被销毁。<strong>而线程则是进程内的一个独立执行单元，</strong>在不同的线程之间是可以共享进程资源的，所以在多线程的情况下，需要特别注意对临界资源的访问控制。在系统创建进程之后就开始启动执行进程的主线程，而进程的生命周期和这个主线程的生命周期一致，主线程的退出也就意味着进程的终止和销毁。主线程是由系统进程所创建的，同时用户也可以自主创建其它线程，这一系列的<strong>线**</strong>程都会并发地运行于同一个进程中**。</p>
</blockquote>
<h3 id="JavaScript是以单线程的方式运行的"><a href="#JavaScript是以单线程的方式运行的" class="headerlink" title="JavaScript是以单线程的方式运行的"></a>JavaScript是以单线程的方式运行的</h3><hr>
<p><strong>原因：</strong></p>
<p>JavaScript作为一个为用户提供交互的脚本语言，会涉及到Dom的操作，假如采用多进程，会造成操作的冲突。比如一条线程中要删除某个dom元素，而另一条线程却要更改该Dom的样式，就会造成冲突，因为系统无法决定采用哪条线程的操作。虽然可以为浏览器引用‘锁’的机制来解决问题，但会大大提高复杂性，不符合JavaScript的语言特点，所以采用单线程。</p>
<p><strong>运行原理和机制</strong></p>
<p>栈，堆，队列。</p>
<p><img src="http://i.imgur.com/fDlN6a5.png" alt=""></p>
<p>1.栈中放着JS正在执行的任务，完成执行就弹出（后进先出）。</p>
<p>2.堆是一个用来表示内存中一大片非结构化区域的名称，对象被分配于此。</p>
<p>3.队列中放着尚未执行并等待主线程空闲后执行的任务，满足先进先出。</p>
<hr>
<p><strong>任务的执行顺序</strong></p>
<p>异步任务（各种浏览器事件、定时器等）都是先添加到“任务队列”（定时器则到达其指定参数时）。当Stack栈（JS主线程）为空时，就会读取Queue队列（任务队列）的第一个任务（队首），然后执行。</p>
<hr>
<p><strong>定时器</strong>setTimeOut 和setInterval </p>
<p>即使给定时器的第二次参数设置为0，也不会是0延迟，它会被放入队列末尾，等待主线程空闲且前面的任务完成。而且默认第二个参数如果小于4ms，则增加至4ms（HTML5标准）</p>
<hr>
<h4 id="浏览器是多线程的"><a href="#浏览器是多线程的" class="headerlink" title="浏览器是多线程的"></a>浏览器是多线程的</h4><p>浏览器的内核是多线程的，它们在内核制控下相互配合以保持同步，一个浏览器至少实现三个常驻线程。</p>
<ul>
<li>javascript引擎线程 javascript引擎是基于事件驱动单线程执行的，JS引擎一直等待着任务队列中任务的到来，然后加以处理，浏览器无论什么时候都<strong>只有一个JS线程</strong>在运行JS程序。</li>
<li>GUI渲染线程 GUI渲染线程负责渲染浏览器界面，当界面需要重绘（Repaint）或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意<strong>GUI渲染线程与JS引擎线程是互斥的</strong>，当JS引擎执行时GUI线程会被挂起，GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。</li>
<li><strong>浏览器事件</strong>触发线程 事件触发线程，当一个事件被触发时该线程会把事件添加到“任务队列”的队尾，等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等，但由于JS是单线程执行的，所有这些事件都得排队等待JS引擎处理。</li>
</ul>
<p><strong>Chrome浏览器的特性</strong></p>
<blockquote>
<p>在Chrome浏览器中，为了防止因一个标签页奔溃而影响整个浏览器，其每个标签页都是一个进程。当然，对于同一域名下的标签页是能够相互通讯的，具体可看 浏览器跨标签通讯。在Chrome设计中存在很多的进程，并利用进程间通讯来完成它们之间的同步，因此这也是Chrome快速的法宝之一。对于Ajax的请求也需要特殊线程来执行，当需要发送一个Ajax请求时，浏览器会开辟一个新的线程来执行HTTP的请求，它并不会阻塞JavaScript线程的执行，当HTTP请求状态变更时，相应事件会被作为回调放入到“任务队列”中等待被执行</p>
</blockquote>
<p><strong>总结</strong></p>
<ul>
<li>JS是单线程，而浏览器是多线程</li>
<li>单线程采用非阻塞式可以提高单核CPU效率</li>
<li>线程是进程中的独立控制单元，在进程中独立并发进行</li>
<li>浏览器事件任务会被先放入队列中，定时器的任务也会放入队列中，但是等待所设置的时间之后执行，但都会等待主线程空闲时再执行。</li>
<li>同步是阻塞式（synchronous）</li>
<li>异步是非阻塞式（asynchronous）</li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2016/11/20/JavaScript的单线程问题及同步和异步/" data-id="civq9xcq30007f0e5dcxfucrk" class="article-share-link">Share</a>
      
      
    </footer>
  </div>
  
    
<nav id="article-nav">
  
  
    <a href="/2016/11/19/mvc与mvm与mvvm/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">mvc与mvm与mvvm</div>
    </a>
  
</nav>

  
</article>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/CS/">CS</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/JS/">JS</a></li></ul>
    </div>
  </div>


  
    

  
    
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/11/">十一月 2016</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/11/20/JavaScript的单线程问题及同步和异步/">JavaScript的单线程问题及同步和异步</a>
          </li>
        
          <li>
            <a href="/2016/11/19/mvc与mvm与mvvm/">mvc与mvm与mvvm</a>
          </li>
        
          <li>
            <a href="/2016/11/19/分类介绍/">分类介绍</a>
          </li>
        
          <li>
            <a href="/2016/11/18/Git的诞生/">Git的诞生</a>
          </li>
        
          <li>
            <a href="/2016/11/17/learn-how-to-build-your-Blog/">learn how to build your Blog</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 AcerY<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">主页</a>
  
    <a href="/categories/JS" class="mobile-nav-link">JavaScript</a>
  
    <a href="/categories/CS" class="mobile-nav-link">ComputerScience</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>

  </div>
</body>
</html>